<?php
namespace Game\Models;

use Game\Lib\CodeConst;
use Game\Models\Common\MysqlData;
use Game\Models\Common\RedisData;
use Game\Module\Logger;
use Game\Module\Tools;
use GatewayWorker\Lib\Gateway;
use Game\Lib\GlobalConst;
use Game\Lib\RedisConst;
use Game\Lib\Game;
use Game\Lib\OptConst;
use Game\Config\Config;
use Game\Module\Socket;


class PublicModel
{
	use RedisData;
	use MysqlData;

	public $client_id;
	public $room_id;
	public $account_id;
	public $operation;
	public $session;
	public $data;

	/**
	 * 写日志
	 * @param $level
	 * @param $content
	 */
	public function logMessage($level,$content)	{
		if ($level == "debug"){
			$this->writeDebugLog($content);
		}elseif($level == "error") {
			$this->writeErrorLog($content);
		}else {
			$this->writeLog($content);
		}
	}
	/**
	 * 写日志
	 * @param $content
	 */
	public function writeLog($content){
	    Logger::getInstance()->info( $content );
	}

	public function writeDebugLog($content){
        Logger::getInstance()->debug( $content );
	}
	public function writeErrorLog($content){
        Logger::getInstance()->error( $content );
	}

    public function getTicketUse($prameter)
    {
        $val = "";
        foreach (Game::TicketUse_Key as $key) {
            $val .= $prameter[$key].":";
        }
        $return = isset(Game::TicketUse_Val[trim($val, ":")]) ? Game::TicketUse_Val[trim($val, ":")] : -1;
        return $return;
    }

    public function getRoomPassword(){
        $ti = microtime();
        list($s,$m) = explode(" ", $ti);
        $newRoomNumber = substr($m + substr($s,2), 4);
        if ($newRoomNumber <= 100000) $newRoomNumber += 100000;
        if ($this->hexistsRoomPasswordKey($newRoomNumber) == RedisConst::Key_Nonexistent){
            return $newRoomNumber;
        }else{
            return $this->getRoomPassword();
        }
    }

    /**
     * 设置 自动弃牌 定时器
     * @param $room_id
     * @param $account_id
     */
	protected function setupDiscardPassiveTimer($room_id, $account_id){
		$callback_array = array(
			'operation' => "DiscardPassive",
			'room_id' => $room_id,
			'data' => array(
				'account_id' => $account_id
			)
		);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Betting,
				'callback_array' => $callback_array
			)
		);
		$this->sendToTimerServer($arr);

		$this->setTimerTime($room_id);  //分开、提前设置时间
	}

    /**
     * 设置 自动开局 定时器
     * @param $room_id
     */
	protected function setupStartGamePassiveTimer($room_id){

		$limit_time = $this->queryGameNumber($room_id) > 0 ? Game::LimitTime_Ready : Game::LimitTime_StartGame;

		$callback_array = array(
			'operation' => "StartGamePassive",
			'room_id' => $room_id,
			'data' => array(
			)
		);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => $limit_time,
				'callback_array' => $callback_array
			)

		);
		$this->sendToTimerServer($arr);

		$this->setTimerTime($room_id);  //分开、提前设置时间

		$arr = array("result"=>0,"operation"=>"StartLimitTime","data"=>array('limit_time' => $limit_time),"result_message"=>"开始倒计时");
		$this->pushMessageToGroup($room_id, $arr);
	}


    /**
     * 设置 清理房间 定时器
     * @param $room_id
     */
	protected function setupClearRoomPassiveTimer($room_id){
		$this->writeLog("[$room_id] 设置自动清扫房间定时器");
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_ClearRoom,
				'callback_array' => array(
					'operation' => "ClearRoomPassive",
					'room_id' => $room_id,
					'data' => array(
					)
				)
			)
		);
		$this->sendToTimerServer($arr);

		//$this->setTimerTime($room_id);    //分开、提前设置时间   (这个清扫定时器就暂不设置时间了)
	}


    /**
     * 删除定时器
     * @param $room_id
     */
	protected function deleteRoomTimer($room_id){
		$timer_id = $this->queryTimerId($room_id);
		if($timer_id > 0){
			$arr = array(
				'operation' => "DeleteTimer",
				'room_id'   => $room_id,
				'data' => array(
					'timer_id' => $timer_id
				)
			);
			$this->sendToTimerServer($arr);
		}
		$this->updateTimer($room_id, -1);
	}



	//自增长房间当前局数、轮数
	protected function updateGameNumberRound($room_id){
		$game_num = $this->hincrbyRoomKey($room_id,RedisConst::Room_Field_GameNum,1);
		$this->writeLog("[$room_id] 新的一局 :".$game_num);
		if($game_num == 1){
			//设置开局时间
			$this->updateStartTime($room_id);
		}

	}

	//更新用户状态
	protected function updateAccountStatus($room_id, $account_id, $status){
		$mkv[$account_id] = $status;
		$this->updateAccountStatusKey($room_id,$mkv);

		//广播用户状态改变
		$noty_arr = array(
			'account_id' => $account_id,
			'account_status'=>$status,
			'online_status'=>$this->queryOnlineStatus($room_id, $account_id)
		);
		$this->writeLog("[$room_id] ($account_id) 状态改变 ". $status);
		$this->notyUpdateAccountStatusToGroup($room_id, $noty_arr);
	}

	//获取在线状态
	protected function queryOnlineStatus($room_id, $account_id){
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);

		return Gateway::isUidOnline($RoomUser_UID);
	}


	//获取准备人数
	protected function queryReadyCount($room_id){
		$result = $this->queryAccountStatusKey($room_id);
		$count = 0;
		if(RedisConst::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$count++;
				}
			}
		}
		return $count;
	}

	//获取准备的人
	protected function queryReadyUser($room_id){
		$result = $this->queryAccountStatusKey($room_id);
		if(RedisConst::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$ready_user_array[] = $account_id;
				}
			}
		}
		return $ready_user_array;
	}
	//观战功能 (修改) 获取在房(入座)的人
	protected function queryInRoomUser($room_id){
		$in_room_user_array = [];
		$room_members = $this->queryRoomMembers($room_id);
		$guests = $this->lrangeRoomGuestKey($room_id);
		$room_members = array_diff($room_members, $guests);

		foreach ($room_members as $account_id) {
			if($this->queryOnlineStatus($room_id, $account_id)){
				$in_room_user_array[] = $account_id;
			}
		}
		return $in_room_user_array;
	}



	//获取用户是否已经看牌
	protected function querySeenCard($room_id, $account_id){
		$result = $this->querySeenCardKey($room_id, $account_id);
		return $result == 1 ? 1 : 0;
	}


	//下注平衡积分
	protected function balanceScore($room_id, $account_id, $score){
		$this->hincrbyRoomScoreKey($room_id,$account_id,0 - $score);//总分 减少
		$this->hincrbyPlayKey($room_id,RedisConst::Play_Field_PoolScore,$score);
		$this->hincrbyChipKey($room_id,$account_id, $score);
	}

	//获胜平衡积分  account_id 下注者
	protected function balanceWinnerScore($room_id, $winners, $account_id=-1){
		$winner_score_dict = array();
		$count = count($winners);
		if($count < 1){
			return array();
		}

		$pool_score = $this->queryPlayKey($room_id, RedisConst::Play_Field_PoolScore);
		$per_score = intval($pool_score/$count);
		$remain_score = $pool_score - $per_score * ($count-1) ;

		foreach ($winners as $winner_id) {
			if($winner_id == $account_id){
				$win_score = $remain_score;
			} else {
				$win_score = $per_score;
			}
			$this->hincrbyRoomScoreKey($room_id,$winner_id,$win_score);//个人总分 增加
			$winner_score_dict[$winner_id] = $win_score;
		}
		$this->updatePlayKey($room_id,array(RedisConst::Play_Field_PoolScore => 0));   //分数池 清零
		return $winner_score_dict;
	}

	protected function caculateCardValue($room_id, $player_id){
		$card_str = $this->queryCardKey($room_id, $player_id);
		$cards = explode(",", $card_str);
		return $this->_cardValue($cards);
	}
	protected function _cardValue($cards){

		if(count($cards)!=3){
			return 0;
		}
		$value = 0;
		$suits = array();
		$points= array();
		foreach ($cards as $card) {
			$suits[] = substr($card, 0, 1);
			$points[] = substr($card, 1);
		}

		//A替换成数值14
		for ($i=0; $i < count($points); $i++) {
			if($points[$i] == 1){
				$points[$i] = 14;
			}
		}

		rsort($points, SORT_NUMERIC);  //大到小排序
		$points_val_str = str_pad($points[0], 2, "0", STR_PAD_LEFT) . str_pad($points[1], 2, "0", STR_PAD_LEFT) . str_pad($points[2], 2, "0", STR_PAD_LEFT);
		//牌型  0未知(因别人弃牌而胜) 1高牌 2对子 3顺子 4同花 5同花顺 6三条
		if($points[0] == $points[2]){ //三条
			$value = "6".$points_val_str;
		} else if($points[0] == $points[1]){ //对子
			$value = "2".$points_val_str;
		} else if($points[1] == $points[2]){ //对子
			$value = "2".str_pad($points[2], 2, "0", STR_PAD_LEFT) . str_pad($points[1], 2, "0", STR_PAD_LEFT) . str_pad($points[0], 2, "0", STR_PAD_LEFT);
		} else if($points[0] == $points[2] + 2){ //顺子
			$card_type = ($suits[0] == $suits[1] && $suits[1] == $suits[2]) ? 5 : 3;
			$value = $card_type.$points_val_str;
		} else if($points[0]==14&&$points[1]==3&&$points[2]==2){ //顺子
			$card_type = ($suits[0] == $suits[1] && $suits[1] == $suits[2]) ? 5 : 3;
			$value = $card_type."010203";
		} else if($suits[0] == $suits[1] && $suits[1] == $suits[2]){  //同花
			$value = "4".$points_val_str;
		} else {    //高牌
			$value = "1".$points_val_str;
		}
		return $value;
	}

	protected function queryCardInfo($room_id, $player_id){
		$card_str = $this->queryCardKey($room_id, $player_id);
		$this->writeLog("[$room_id] ($player_id) 手牌:".$card_str);
		if(RedisConst::DATA_NONEXISTENT === $card_str || ""==trim($card_str)){  //异常状态返回空数组
			$this->writeLog("function(queryCardInfo):异常状态返回空数组"." in file".__FILE__." on Line ".__LINE__);
			return array();
		}
		$cards = explode(",", $card_str);

		return $cards;
	}



	//轮流
	protected function takeTurns($room_id){
		$this->rpoplpushPlayMemberKey($room_id);
		$list = $this->lrangePlayMemberKey($room_id,-1,-1);  //队列最右边是当前操作用户
		if($list){
			$account_id = $list[0];
		} else {
			$account_id = -1;
		}

		$mkv[RedisConst::Play_Field_ActiveUser] = $account_id;
		$this->updatePlayKey($room_id,$mkv);
		return $account_id;
	}



	//从游戏中队列踢出
	protected function removeFromPlayMember($room_id, $account_id){
		$this->lremPlayMemberKey($room_id, 0, $account_id);
		$list = $this->lrangePlayMemberKey($room_id,-1,-1); //队列最右边是当前操作用户
		if($list){
			$active_id = $list[0];
		} else {
			$active_id = -1;
		}
		$mkv[RedisConst::Play_Field_ActiveUser] = $active_id;
		$this->updatePlayKey($room_id,$mkv);
		return $active_id;
	}

	//推消息
	protected function pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null){
		$msg = Tools::getInstance()->jsonEncode($msg_arr);
		Gateway::sendToGroup($room_id, $msg, $exclude_client_id);
	}
	protected function pushMessageToAccount($room_id, $account_id, $msg_arr){
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);
		$msg = Tools::getInstance()->jsonEncode($msg_arr);
		Gateway::sendToUid($RoomUser_UID, $msg);
	}
	protected function pushMessageToCurrentClient($msg_arr){
		$msg = Tools::getInstance()->jsonEncode($msg_arr);
		Gateway::sendToCurrentClient($msg);
	}

	//广播用户状态改变
	protected function notyUpdateAccountStatusToGroup($room_id, $noty_arr, $exclude_client_id=null){

		if(!isset($noty_arr['account_id']) || !isset($noty_arr['account_status']) ){
			$this->writeLog("function(notyUpdateAccountStatusToGroup):lack of params"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$msg_arr = array("result"=>"0","operation"=>"UpdateAccountStatus","data"=>$noty_arr,"result_message"=>"用户状态改变");
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null);
	}


	//是否经过了第一轮下注，经过了才能比牌
	protected function pkChipConditon($room_id, $account_id){
		$disable_pk_100 = $this->queryRoomKey($room_id,RedisConst::Room_Field_DisablePk100);
		if($disable_pk_100){
			if($this->queryPoolScore($room_id) < 100){
				return 0;
			}
		}
		$betScore = $this->queryChipKey($room_id, $account_id);
		$defScore = $this->queryRoomKey($room_id, RedisConst::Room_Field_DefaultScore);
		if($betScore <= $defScore ){
			return 0;
		}
		return 1;
	}

	//是否经过了第一轮下注，经过了才能看牌
	protected function lookConditon($room_id, $account_id){
		$disable_look = $this->queryRoomKey($room_id,RedisConst::Room_Field_DisableLook);
		if($disable_look){
			$betScore = $this->queryChipKey($room_id, $account_id);
			$defScore = $this->queryRoomKey($room_id, RedisConst::Room_Field_DefaultScore);
			if($betScore <= $defScore ){
				return 0;
			}
		}
		return 1;
	}

	//通知用户下注
	protected function notyUserToBet($room_id, $account_id){

		$can_open = 0;
		$pk_user = array();
		if($this->pkChipConditon($room_id, $account_id)){
			$pk_user = $this->queryPkUser($room_id, $account_id);
			if(count($pk_user) > 0){
				$can_open = 1;
			}
		}

		//$this->writeLog("轮到用户".$account_id. "下注 (can_open:". $can_open .")");

		//设置自动弃牌定时器
		$this->setupDiscardPassiveTimer($room_id, $account_id);

		$noty_arr = array(
			'account_id' => $account_id,
			'playing_status' => Game::PlayingStatus_Betting,
			'limit_time'     => Game::LimitTime_Betting,
			'can_open' => $can_open,
			'pk_user' => $pk_user,
			'can_look' => $this->lookConditon($room_id, $account_id)
		);
		$msg_arr = array("result"=>"0","operation"=>"NotyChooseChip","data"=>$noty_arr,"result_message"=>"通知下注");
		$this->pushMessageToGroup($room_id, $msg_arr);
	}

	public function queryPkUser($room_id, $account_id){
		$players = $this->lrangePlayMemberKey($room_id);
		$other_players = array();
		foreach ($players as $player_id) {
			if($player_id != $account_id){
				$other_players[] = $player_id;
			}
		}
		$other_count = count($other_players) ;
		if($other_count == 1){
			$pk_user = $other_players;
		} else {
			$pk_user = array();
			foreach ($other_players as $player_id) {
				$status = $this->queryAccountStatus($room_id, $player_id);
				if($status == Game::AccountStatus_Visible){ //对方是看牌状态才能比牌
					$pk_user[] = $player_id;
				}
			}
			if(count($pk_user) < $other_count ){ //有人闷牌
				$setting = $this->queryRoomKey($room_id);
				$disable_pk_men=isset($setting[RedisConst::Room_Field_DisablePkMen]) ?$setting[RedisConst::Room_Field_DisablePkMen]:0;
				if($disable_pk_men){
					$pk_user = array();
				}
			}
		}
		return $pk_user;
	}
	protected function queryInRoomPlay($room_id){
		$in_room_user_array = [];
		$room_members = $this->queryRoomMembers($room_id);
		$guests = $this->lrangeRoomGuestKey($room_id);
		$room_members = array_diff($room_members, $guests);

		foreach ($room_members as $account_id) {
			if($this->queryOnlineStatus($room_id, $account_id) && $this->queryAccountStatus($room_id,$account_id)>2){
				$in_room_user_array[] = $account_id;
			}
		}
		return $in_room_user_array;
	}


	//喜牌平衡积分
	protected function balanceXipaiScore($room_id, $winner_id){
		if (!is_array($winner_id)){
			$winner_id = [$winner_id];
		}

		$score = $this->queryRoomKey($room_id, RedisConst::Room_Field_XiPai);
		$this->writeLog( "喜牌：$score");
		$players = $this->queryInRoomPlay($room_id);
		$account_count = count($players);
		$xipai_score_dict = [];
		$this->writeLog("赢家：".json_encode($winner_id));
		foreach ($players as $mem_id) {
			if(in_array($mem_id,$winner_id )){
				$this->writeLog("喜牌[$room_id][$mem_id]：+". ($score*($account_count-1)));
				$this->hincrbyRoomScoreKey($room_id, $mem_id, $score*($account_count-1));
				$xipai_score_dict[$mem_id] = "+".$score*($account_count-1);
			} else {
				$this->writeLog( "喜牌[$room_id][$mem_id]：-".$score);
				$this->hincrbyRoomScoreKey($room_id,$mem_id, 0 - $score); //总分 减少
				$xipai_score_dict[$mem_id] =  0 - $score;
			}
		}
		return $xipai_score_dict;
	}
	/*
        一局输赢结果
        win_type 结局   1开牌   2弃牌    3封顶自动开牌
    */

	public function showWin($room_id, $account_id, $next_account_id, $win_type){
		$success = $this->setRoomStatusTransaction($room_id, 2, 1);
		if(!$success){
			$this->writeLog("并发 showWin ，忽略。room id:".$room_id."。in file".__FILE__." on Line ".__LINE__);
			return false;
		}
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(RedisConst::PlayMember_Key, $replyArr);


		$player_cards = array();  //索引数组
		$winner_score_dict = array();
		$xipaiScore = $this->queryRoomKey($room_id, RedisConst::Room_Field_XiPai);
		if(1 == $win_type){ //开牌结局

			$cards1 = $this->queryCardInfo($room_id, $account_id);
			$value1 = $this->_cardValue($cards1);

			$cards2 = $this->queryCardInfo($room_id, $next_account_id);
			$value2 = $this->_cardValue($cards2);

			if($value1 > $value2){
				$winner_id = $account_id;
				$card_type = substr($value1, 0, 1);
			} else {
				$winner_id = $next_account_id;
				$card_type = substr($value2, 0, 1);
			}
			$_card_type = $card_type;
			$player_cards[] = array(
				'account_id'=> $account_id,
				'cards' => $cards1
			);
			$player_cards[] = array(
				'account_id'=> $next_account_id,
				'cards' => $cards2
			);

			if($winner_id > 0){
				$winner_score_dict = $this->balanceWinnerScore($room_id, [$winner_id], $account_id);
			}
			$winners[] = $winner_id;
		} else if(2 == $win_type){  //弃牌结局
			$winner_id = ($next_account_id != -1) ? $next_account_id : $account_id;
			$cards = $this->queryCardInfo($room_id, $winner_id);
			$value = $this->_cardValue($cards);
			$_card_type = substr($value, 0, 1);

			if ($_card_type >= 5 && $xipaiScore > 0){//判断是否喜牌并且开启喜牌
				$player_cards[] = array(
					'account_id'=> $winner_id,
					'cards' => $cards
				);
				$card_type = $_card_type;
			}else{
				$card_type = 0;
			}
			if($winner_id > 0){
				$winner_score_dict = $this->balanceWinnerScore($room_id, [$winner_id], $account_id);
			}
			$winners[] = $winner_id;
		} else { //封顶自动开牌
			$winners = array();
			$players = $this->lrangePlayMemberKey($room_id);
			$card_value_array = array();  //关联数组
			$max_value = 0;
			$_card_type = 0;
			foreach ($players as $player_id) {

				$cards = $this->queryCardInfo($room_id, $player_id);
				$value = $this->_cardValue($cards);
				$card_value_array[$player_id] = $value;
				if($value > $max_value){
					$max_value = $value;
					$card_type = substr($max_value, 0, 1);
					$_card_type = $card_type;
				}
				//手牌
				$player_cards[] = array(
					'account_id'=> $player_id,
					'cards' => $cards
				);
			}

			$this->writeLog("[$room_id] choose Winner:");
			foreach ($card_value_array as $winner_id => $value) {
				$this->writeLog("[$room_id] ".$winner_id." => ".$value);
				if($value == $max_value){
					$winners[] = $winner_id;
					$this->writeLog("[$room_id] --------------");
				}
			}
			$winner_score_dict = $this->balanceWinnerScore($room_id, $winners, $account_id);
		}
		$xipai_score_dict = [];
		$this->writeLog("[".$room_id."] _card_type:". $_card_type);
		$this->writeLog("[".$room_id."] player_cards:".json_encode($player_cards));
		if ($_card_type >=5 ){//判断是否喜牌并且开启喜牌
			$xipai_score_dict = $this->balanceXipaiScore($room_id, $winners);
		}
		if(count($winner_score_dict) > 0){
			$scoreboard = $this->queryRoomScoreKey($room_id);
			//保存积分榜
			if(is_array($scoreboard)){
				$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
				foreach ($scoreboard as $account_id => $score) {
					if(!in_array($account_id, $ticket_checked_user)){
						//未扣房卡的用户不显示在积分榜上
						unset($scoreboard[$account_id]);
					}
				}
				$board_json_str = json_encode($scoreboard);

			} else {
				$scoreboard = array();
				$board_json_str = "";
			}
			$mkv[RedisConst::Room_Field_Scoreboard] = $board_json_str;
			$this->updateRoomKey($room_id, $mkv);

			$start_time = $this->queryStartTime($room_id);
			$game_num = $this->queryGameNumber($room_id);
			$total_num = $this->queryTotalNum($room_id);
			$msg_arr = array(
				'result' => 0,
				'operation' => 'Win',
				'result_message' => "获胜+积分榜",
				'data' => array(
					'player_cards' => $player_cards,
					'card_type' => $card_type,
					'score_board' => $scoreboard,
					'game_num' => $game_num,
					'total_num' =>  $total_num,
					'winner_score_dict' => $winner_score_dict,
					'xipai_score_dict'=>$xipai_score_dict,
				)
			);

			$this->pushMessageToGroup($room_id, $msg_arr);

			//保存当局游戏结果
			$setting = $this->queryRoomKey($room_id);
			$round = $setting[RedisConst::Room_Field_GameRound];

			$game_info['room_id'] = $room_id;
			$game_info['game_type'] = Game::Game_Type;
			$game_info['dealer_num'] = Config::Dealer_Num;
			$game_info['round'] = $round;
			$game_info['game_num'] = $game_num;
			$game_info['total_num'] = $total_num;
			$game_info['extra'] = "";
			$this->saveGameResult($game_info);


			//$this->updateRoomStatus($room_id, 1);   //房间状态，1等待、2进行中、3关闭
			if($game_num == $total_num){  //最后一局

				$this->hincrbyRoomKey($room_id, RedisConst::Room_Field_GameRound, 1);
				$this->writeLog("[$room_id] 第".($round-1)."轮 结束!");

				$name_board = array();
				foreach ($scoreboard as $account_id => $score) {
                    $name = $this->getAccountNickName($account_id);
					$name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
				}

				//规则文本
				$rule_text = $this->formatRuleText($room_id);
				$balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
				$balance_board_json_str = json_encode($balance_scoreboard['scoreboard']);
				//保存积分榜
				$board_array['start_time'] = $start_time;

				$board_array['create_time'] = time();
				$board_array['is_delete'] = GlobalConst::IS_FALSE;
				$board_array['game_type'] = Game::Game_Type;  //游戏类型
				$board_array['room_id'] = $room_id;
				$board_array['round'] = $round-1;
				$board_array['game_num'] = $game_num;

				$board_array['rule_text'] = $rule_text;
				$board_array['board'] = $board_json_str;
				$board_array['balance_board'] = $balance_board_json_str;
                $this->insertRoomScoreboard($board_array);
				//保存用户积分
				$game_info['score_board'] = $scoreboard;
				$this->saveAccountGameScore($game_info);

				//清理房间
				$this->clearRoom($room_id);

			} else {
				$this->resetAllAccountStatus($room_id);  //重设所有用户状态为未准备

				//删除每局游戏参数
				$this->deletePlayKey($room_id);
				$this->deletePlayMemberKey($room_id);
				$this->deleteChipKey($room_id);
				$this->deleteCardKey($room_id);
				$this->deleteSeenCardKey($room_id);
			}

		} else {
			$this->logMessage('error', "数据错误:function(openCard):have no winner!");
		}
	}

	//清理房间
	protected function clearRoom($room_id){
		$room_password = $this->queryRoomKey($room_id, RedisConst::Room_Field_Password);

		//删除每轮游戏参数
		$this->deleteRoomSequenceKey($room_id);
		$this->deleteRoomGuestKey($room_id);
		$this->deleteAccountStatusKey($room_id);
		$this->deleteRoomScoreKey($room_id);

		//删除每局游戏参数
		$this->deleteSeenCardKey($room_id);
		$this->deleteChipKey($room_id);
		$this->deleteCardKey($room_id);
		$this->deletePlayMemberKey($room_id);
		$this->deletePlayKey($room_id);

		if(Config::Room_IsReuse == 1){  //可以重复利用房间
			$r_mkv[RedisConst::Room_Field_GameNum] = 0;            //游戏局数
			$r_mkv[RedisConst::Room_Field_DefaultScore] = Game::Default_Score;     //开局默认分数
			$r_mkv[RedisConst::Room_Field_Scoreboard] = "";        //积分榜清零
			$r_mkv[RedisConst::Room_Field_Creator] = -1;       //创建者清空
			$r_mkv[RedisConst::Room_Field_Status] = Game::RoomStatus_Closed;   //房间状态，1等待、2进行中、3未激活
			$r_mkv[RedisConst::Room_Field_StartTime] = -1;
			$this->updateRoomKey($room_id, $r_mkv);
		} else {  //玩一轮即销毁
			$this->updateRoom($room_id,['is_close'=>1]);

			$this->deleteRoomPasswordKey($room_password);
			$this->deleteRoomKey($room_id);
		}
		$this->writeLog("[$room_id] 房间清理完毕!");
	}

	//整理规则内容文本
	protected function formatRuleText($room_id,$room_data=""){
		$rule_text = "";
		$setting = $this->queryRoomKey($room_id);
		$ticket_count=isset($setting[RedisConst::Room_Field_TicketCount]) ?$setting[RedisConst::Room_Field_TicketCount]:1;
		$chip_type= isset($setting[RedisConst::Room_Field_ChipType])?$setting[RedisConst::Room_Field_ChipType]:1;
		$disable_pk_100=isset($setting[RedisConst::Room_Field_DisablePk100]) ?$setting[RedisConst::Room_Field_DisablePk100]:0;
		$disable_pk_men=isset($setting[RedisConst::Room_Field_DisablePkMen]) ?$setting[RedisConst::Room_Field_DisablePkMen]:0;
		$disable_look=isset($setting[RedisConst::Room_Field_DisableLook]) ?$setting[RedisConst::Room_Field_DisableLook]:0;
		$only_big=isset($setting[RedisConst::Room_Field_Onlybig]) ?$setting[RedisConst::Room_Field_Onlybig]:0;
		$upper_limit   =isset($setting[RedisConst::Room_Field_UpperLimit]) ?$setting[RedisConst::Room_Field_UpperLimit]:1000;
		$xipai_score   =isset($setting[RedisConst::Room_Field_XiPai]) ?$setting[RedisConst::Room_Field_XiPai]:0;
		//局数房卡规则
		$game_multi = Config::GameUser_MaxCount==9 ? 2 : 1;
		$ticket_count = $ticket_count * $game_multi * Config::Ticket_Multi;
		$ticket_type_text = $setting[RedisConst::Room_Field_TotalNum]."局/".$ticket_count."张房卡";
		$rule_text .= $ticket_type_text;

		//筹码类型
		$rule_text .= ",";
		switch($chip_type)
		{
			case 1:
				$rule_text .= "筹码:2/5,4/10,8/20,10/25";
				break;
			case 2:
				$rule_text .= "筹码:4/10,8/20,10/25,20/50";
				break;
		}

		if($disable_pk_100 )
		{
			$rule_text .= ",100分以下不能比牌";
		}
		if($disable_pk_men )
		{
			$rule_text .= ",闷牌禁止比牌";
		}
		if($disable_look )
		{
			$rule_text .= ",首轮不能看牌";
		}
		if($only_big )
		{
			$rule_text .= ",只发AKQJ10模式";
		}
		//封顶上限
		if($upper_limit > 0){
			$rule_text .= ",上限:".$upper_limit."分";
		} else {
			$rule_text .= ",上限:无";
		}
		if($xipai_score > 0){
			$rule_text .= ",喜牌:".$xipai_score."分";
		} else {
			$rule_text .= ",喜牌:无";
		}
		return $rule_text;
	}


	/*
        保存炸金花游戏结果
    */
	protected function saveGameResult($game_info){
		$timestamp = time();
		$room_id = $game_info['room_id'];
		$game_type = $game_info['game_type'];

		$game_data['time'] = time();
		$game_data['rid'] = $game_info['room_id'];
		$game_data['rnd'] = $game_info['round'];
		$game_data['gnum'] = $game_info['game_num'];
		$game_data['tnum'] = $game_info['total_num'];

		//获取所有人手牌
		$card_array = $this->queryCardKey($room_id);
		$chip_array  = $this->queryChipKey($room_id);
		$room_members = $this->queryRoomMembers($room_id);
		$player_array = array();    //玩家当局数据
		//获取用户名字
		$names = array();
		if(count($room_members)>0){
            $rows = $this->getAccountListByIDs($room_members);
			if(is_array($rows)){
				foreach ($rows as $item) {
					$names[$item['account_id']] = $item['nickname'];
				}
			}
		}

		foreach($room_members as $player_id) {
			if(!isset($chip_array[$player_id]) || !isset($card_array[$player_id])){
				continue;
			}

			$array['p'] = $player_id;
			$array['s'] = $chip_array[$player_id];
			$array['c'] = $card_array[$player_id];

			$value = $this->caculateCardValue($room_id, $player_id);
			$card_type = substr($value, 0, 1);

			$array['ct'] = $card_type;

			//获取用户名字
			$array['n'] = isset($names[$player_id])?$names[$player_id]:"";

			$player_array[] = $array;
			unset($array);
		}

		$save_game_result['pAry'] = $player_array;
		$save_game_result['gData'] = $game_data;
		$save_game_result_json = json_encode($save_game_result);

		$round = $game_data['rnd'];
		$array['create_time'] = $timestamp;
		$array['game_type'] = $game_type;
		$array['room_id'] = $room_id;
		$array['round'] = $round;
		$array['game_result'] = $save_game_result_json;

        $this->insertRoomGameResult($array);
		unset($array);
		return true;
	}

	protected function saveAccountGameScore($game_info)
	{
		$timestamp = time();
		//$cols = array('create_time','game_time','is_delete','room_id','game_type','round','account_id','score');
		if(is_array($game_info['score_board'])){
			foreach ($game_info['score_board'] as $account_id => $score) {
				//$values[] = array($timestamp, $timestamp, 0, $game_info['room_id'], $game_info['game_type'], $game_info['round'], $account_id, $score);
				$cols = array('create_time'=>$timestamp,'game_time'=>$timestamp,'is_delete'=>0,'room_id'=>$game_info['room_id'],'game_type'=>$game_info['game_type'],'round'=>$game_info['round'],'account_id'=> $account_id,'score'=>$score);
                $this->insertRoomGameScore($cols);
			}
		}
	}


	//发牌 全随机规则
	protected function dealCard($player_count, $only_big=false){
		$player_cards = array();
		if(!$only_big){
			$Card = array("A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13",
				"B1","B2","B3","B4","B5","B6","B7","B8","B9","B10","B11","B12","B13",
				"C1","C2","C3","C4","C5","C6","C7","C8","C9","C10","C11","C12","C13",
				"D1","D2","D3","D4","D5","D6","D7","D8","D9","D10","D11","D12","D13"
			);
		} else {
			$Card = array("A1","A10","A11","A12","A13",
				"B1","B10","B11","B12","B13",
				"C1","C10","C11","C12","C13",
				"D1","D10","D11","D12","D13"
			);
		}
		mt_srand();
		$indexs = array_rand($Card, 3 * $player_count);
		shuffle($indexs);
		$num = 0;
		for ($i=0; $i < $player_count; $i++) {
			$card_str = $Card[$indexs[$num]].','. $Card[$indexs[$num+1]] .','.$Card[$indexs[$num+2]];
			$player_cards[] = $card_str;
			$num += 3;
			$this->writeLog($card_str);
		}
//      $staticCards = [
//          "A1,B1,C1",
//          "D4,B2,C3",
//          "A2,A3,A4",
//          "B3,B4,B5",
//          "D5,D6,D7",
//          "D12,D13,D1",
//          "A12,B12,C13",
//          "A10,B10,C10",
//      ];
//      shuffle($staticCards);
//      for ($i=0; $i < $player_count; $i++) {
//          $player_cards[]=$staticCards[$i];
//      }
		return $player_cards;
	}


	/*
        推给定时器服务器
    */
	public function sendToTimerServer($msg_array = ""){
		$message = Tools::getInstance()->jsonEncode($msg_array);
		Socket::getInstance()->sendMessageToSocket("Timer",$message);
		return true;
	}



	/**
	 * 返回缺参结果
	 * @param $operation
	 * @param $prameter
	 * @return array
	 */
	protected function _missingPrameterArr($operation,$prameter)
	{
		return array('result'=>CodeConst::Missing_Parameter,'operation'=>$operation,'data'=>array("missing_parameter"=>$prameter),'result_message'=>"缺少参数");
	}


	/**
	 * 生成微秒
	 * @return string
	 */
	protected function getMicroTimestamp()
	{
		$mtime=explode(' ',microtime());
		$mTimestamp=$mtime[1] . substr($mtime[0],2,3);
		return $mTimestamp;
	}

	/**
	 * 判断请求链接合法性
	 * @param $client_id
	 * @param $room_id
	 * @param $account_id
	 * @return bool
	 */
	protected function checkRequestClientLegal($client_id,$room_id,$account_id)
	{
		return true;
		//绑定用户UID
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$room_aid = strtr(Game::RoomUser_UID, $replyArr);

		$client_array = Gateway::getClientIdByUid($room_aid);
		if(is_array($client_array) && count($client_array) > 0)
		{
			foreach($client_array as $bind_client)
			{
				if($bind_client == $client_id)
				{
					return true;
				}
			}
		}
		return false;
	}


}
